#include <QtGui/QHeaderView>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>

#include "profileevaluator.h"
#include "prowriter.h"
#include "procommandmanager.h"
#include "proitems.h"
#include "valueeditor.h"

#include "scopelist.h"
#include "detailsview.h"
#include "editorview.h"

using namespace Qt4ProjectManager::Internal;

ProjectFileEditorView::ProjectFileEditorView(QWidget *parent) : QWidget(parent), m_infomanager(new ProItemInfoManager(this)), m_model(0), m_explorerView(new QTreeView), m_detailsView(new DetailsView), m_valueView(new ValueEditor), m_advanced(new QCheckBox)
{
    m_explorerView->header()->setVisible(false);
    m_advanced->setText(tr("Advanced Mode"));

    connect(m_advanced, SIGNAL(toggled(bool)), this, SLOT(enableAdvanced(bool)));

    QHBoxLayout *hLayout = new QHBoxLayout;
    setLayout(hLayout);
    QVBoxLayout *vLayout = new QVBoxLayout;
    hLayout->addLayout(vLayout);
    vLayout->setMargin(0);
    vLayout->addWidget(m_explorerView);
    vLayout->addWidget(m_detailsView);
    vLayout->addWidget(m_advanced);
    hLayout->addWidget(m_valueView);

    adaptPalette(this);
    adaptPalette(m_explorerView);
    adaptPalette(m_valueView);
    adaptPalette(m_detailsView);
}

ProjectFileEditorView::~ProjectFileEditorView()
{
    releaseModel(m_model);
}

QMap<QString, ProEditorModel *> &ProjectFileEditorView::modelMap()
{
    static QMap<QString, ProEditorModel *> modelMap;
    return modelMap;
}

QMap<ProEditorModel *, int> &ProjectFileEditorView::modelRefCount()
{
    static QMap<ProEditorModel *, int> modelRefCount;
    return modelRefCount;
}

ProEditorModel *ProjectFileEditorView::aquireModel(const QString &fileName)
{
    if (fileName.isEmpty())
        return 0;

    if (modelMap().contains(fileName))
    {
        ProEditorModel *value = modelMap().value(fileName);
        modelRefCount()[value] +=1;

        return value;
    }

    ProFileEvaluator::Option option;
    ProFileEvaluator reader(&option);

    ProFile *profile = new ProFile(fileName);

    if (!reader.queryProFile(profile))
    {
        delete profile;
        return 0;
    }
    ProEditorModel *model = new ProEditorModel();

    model->setProFiles(QList<ProFile *>() << profile);
    modelMap().insert(fileName, model);
    modelRefCount().insert(model, 1);

    return model;
}

void ProjectFileEditorView::releaseModel(ProEditorModel *editorModel)
{
    modelRefCount()[editorModel] -= 1;

    if (modelRefCount().value(editorModel) <= 0)
    {
        modelMap().remove(modelMap().key(editorModel));

        delete editorModel;
    }
}

void ProjectFileEditorView::updateModel(ProEditorModel *editorModel)
{
    if (!modelMap().values().contains(editorModel))
        return;

    QString fileName = modelMap().key(editorModel);
    ProFileEvaluator::Option option;
    ProFileEvaluator reader(&option);
    ProFile *profile = new ProFile(fileName);

    if (!reader.queryProFile(profile))
    {
        delete profile;
        return;
    }

    QList<ProFile *> oldFiles = editorModel->proFiles();
    editorModel->setProFiles(QList<ProFile *>() << profile);
    qDeleteAll(oldFiles);
}

void ProjectFileEditorView::adaptPalette(QWidget *widget)
{
    widget->setAutoFillBackground(true);

    QPalette pal = widget->palette();
    pal.setColor(QPalette::Window, pal.color(QPalette::Base));
    widget->setPalette(pal);
}

void ProjectFileEditorView::showModel(const QString &fileName)
{
    if (m_model)
        return;

    ProEditorModel *m = aquireModel(fileName);

    if (!m)
        return;

    m_model = m;
    m_model->setParent(this);

    connect(m_model->cmdManager(), SIGNAL(modified()), this, SIGNAL(changed()));
    connect(m_model, SIGNAL(modelReset()), this, SLOT(modelReset()));

    m_detailsView->initialize(m_model, m_infomanager);
    m_valueView->initialize(m_model, m_infomanager);

    m_explorerView->setModel(m_detailsView->filterModel());

    connect(m_explorerView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), m_detailsView, SLOT(selectScope(const QModelIndex &)));
    connect(m_model, SIGNAL(modelReset()), this, SLOT(modelReset()));
    connect(m_detailsView, SIGNAL(itemSelected(const QModelIndex &)), m_valueView, SLOT(editIndex(const QModelIndex &)));
    connect(m_detailsView, SIGNAL(actionChanged(int)), this, SIGNAL(actionChanged(int)));

    modelReset();
}

void ProjectFileEditorView::reload()
{
    if (!m_model)
        return;

    updateModel(m_model);
    modelReset();
}

bool ProjectFileEditorView::save()
{
    if (!m_model)
        return false;

    ProWriter writer;
    ProFile *proFile = m_model->proFiles().first();

    if (writer.write(proFile, proFile->fileName()))
    {
        m_model->cmdManager()->notifySave();
        Q_EMIT changed();

        return true;
    }

    return false;
}

bool ProjectFileEditorView::isDirty() const
{
    if (!m_model)
        return false;

    return m_model->cmdManager()->isDirty();
}

void ProjectFileEditorView::enableAdvanced(bool enabled)
{
    if (!m_model)
        return;

    if (enabled)
        m_model->setInfoManager(0);
    else
        m_model->setInfoManager(m_infomanager);
}

QString ProjectFileEditorView::contents() const
{
    if (!m_model)
        return QString();

    ProWriter writer;
    return writer.contents(m_model->proFiles().first());
}

void ProjectFileEditorView::modelReset()
{
    m_explorerView->expandAll();

    if (!m_explorerView->model() || !m_detailsView)
        return;

    QModelIndex scope = m_explorerView->model()->index(0,0);
    m_explorerView->setCurrentIndex(scope);
    m_detailsView->selectScope(scope);
}

bool ProjectFileEditorView::isActionEnabled(int id)
{
    return m_detailsView->isActionEnabled(id);
}

void ProjectFileEditorView::triggerAction(int id)
{
    m_detailsView->triggerAction(id);
}
